//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using C = config;
using DL = Microsoft.Research.DataLayer;

namespace DataLayerBuilder
{
    public partial class DataGen
    {  
        enum ParentClasses
        {
            BasicObject,
            NamedObject,            
        }

        void GenerateObjects(SystemDef sysInfo, GlobalSettingsDef globalSettings, SystemPolicyDef systemPolicy, List<ObjectDef> objList, List<RelationDef> relList, List<EnumDef> enumList)
        {
            string storeTypeFile = Path.Combine(outputFolder,
                string.Format("type_{0}Storage.cs", sysInfo.Name));
            string connTypeFile = Path.Combine(outputFolder,
                string.Format("type_{0}Connection.cs", sysInfo.Name));

            StringBuilder storeTypeList = new StringBuilder();
            StringBuilder connTypeInit = new StringBuilder();
            StringBuilder searchMap = new StringBuilder();
            StringBuilder bindMap = new StringBuilder();

            
            // Create the storage type
            storeTypeList.AppendLine(string.Format("        public static {1}Storage {0} = new {1}Storage(\"{0}\");", "GlobalSetting", sysInfo.Name));
            connTypeInit.AppendLine(string.Format("            TypeStoreMap.Add(typeof({0}), {1}Storage.{0});", "GlobalSetting", sysInfo.Name));
            
            GenerateGlobalSettings(globalSettings, sysInfo);            

            // Create the storage type
            storeTypeList.AppendLine(string.Format("        public static {1}Storage {0} = new {1}Storage(\"{0}\");", "SystemPolicy", sysInfo.Name));
            connTypeInit.AppendLine(string.Format("            TypeStoreMap.Add(typeof({0}), {1}Storage.{0});", "SystemPolicy", sysInfo.Name));

            GenerateSystemPolicy(systemPolicy, sysInfo);
                                    
            foreach (ObjectDef obj in objList)
            {
                // These objects have been added to create the SQL objects alone.
                if (obj.Name.Equals("SystemPolicy") || obj.Name.Equals("GlobalSetting"))
                {
                }
                
                else if (!sysInfo.ImportTypes.Contains(obj.Name))
                {
                    // Create the storage type
                    storeTypeList.AppendLine(string.Format("        public static {1}Storage {0} = new {1}Storage(\"{0}\");", obj.Name, sysInfo.Name));
                    connTypeInit.AppendLine(string.Format("            TypeStoreMap.Add(typeof({0}), {1}Storage.{0});", obj.Name, sysInfo.Name));

                    //
                    // Search helper
                    //
                    List<string> searchClauses = obj.SearchFields;
                    searchMap.AppendLine(string.Format("            SearchMap[{1}Storage.{0}] = new List<string>();", obj.Name, sysInfo.Name));
                    foreach (string clause in searchClauses)
                    {
                        searchMap.AppendLine(string.Format("            SearchMap[{1}Storage.{0}].Add(\"{2}\");", obj.Name, sysInfo.Name, clause));
                    }

                    //
                    // Object generation
                    //
                    if (obj.BaseClass == ParentClasses.NamedObject.ToString())
                    {
                        GenerateNamedObject(sysInfo, obj);
                    }
                    else if (obj.BaseClass == ParentClasses.BasicObject.ToString())
                    {
                        GenerateBasicObject(sysInfo, obj);
                    }                    
                    else
                    {
                        Console.WriteLine("Skipping class '{0}' ({1} not supported yet!)", obj.Name, obj.BaseClass);
                    }
                }
                else
                {
                    Console.WriteLine("Skipping class '{0}' (Imported from parent project)", obj.Name, obj.BaseClass);
                }
            }

            List<string> relObjectGen = new List<string>();

            foreach (RelationDef rel in relList)
            {
                if (rel.Object != null)
                {
                    string objName = string.Format("{0}", rel.Object);

                    if (!relObjectGen.Contains(objName))
                    {
                        relObjectGen.Add(objName);

                        if (!sysInfo.ImportTypes.Contains(objName))
                        {
                            // Create the storage type
                            storeTypeList.AppendLine(string.Format("        public static {1}Storage {0} = new {1}Storage(\"{0}\", Connection.StorageFlags.RelationObject, {2});",
                                objName, sysInfo.Name, rel.IsSelfRelation.ToString().ToLower()));
                            connTypeInit.AppendLine(string.Format("            TypeStoreMap.Add(typeof({0}), {1}Storage.{0});", objName, sysInfo.Name));

                            GenerateRelationObject(sysInfo, rel);
                        }
                        else
                        {
                            Console.WriteLine("Skipping relation '{0}' (Imported from parent project)", objName);
                        }
                    }
                }
                else
                {
                    bindMap.AppendLine(string.Format("            bindingMap.Add(\"{0}-{1}\");", rel.One, rel.Two));
                }
            }

            //
            // Enum type generation
            //

            GenerateEnumTypes(sysInfo, enumList);

            //
            // Storage type generation
            //

            StringBuilder storeTypeCode = new StringBuilder(Properties.Resource1.type_storage);
            storeTypeCode.Replace("%SYSTEM%", sysInfo.Name);
            storeTypeCode.Replace("        %%TYPE_DECL%%\r\n", storeTypeList.ToString());

            using (StreamWriter sw = new StreamWriter(storeTypeFile))
            {
                sw.Write(storeTypeCode);
            }

            //
            // Connection class generation
            //

            StringBuilder classTypeCode = new StringBuilder(Properties.Resource1.type_connection);
            classTypeCode.Replace("%SYSTEM%", sysInfo.Name);

            if (!string.IsNullOrEmpty(sysInfo.DependsOnLayout))
            {
                classTypeCode.Replace("        %%INIT_CODE%%\r\n", Properties.Resource1.type_connection_noinit);
                classTypeCode.Replace("%DEP_SYS%", sysInfo.DependsOnLayout);
            }
            else
            {
                classTypeCode.Replace("        %%INIT_CODE%%\r\n", Properties.Resource1.type_connection_init);
                classTypeCode.Replace("%DEP_SYS%_", "");
            }

            classTypeCode.Replace("            %%TYPE_MAP%%\r\n", connTypeInit.ToString());
            classTypeCode.Replace("            %%SEARCH_MAP%%\r\n", searchMap.ToString());
            classTypeCode.Replace("            %%BIND_MAP%%\r\n", bindMap.ToString());

            using (StreamWriter sw = new StreamWriter(connTypeFile))
            {
                sw.Write(classTypeCode);
            }
        }

        static FieldDef ConvertFromEnumDef(EnumDef src)
        {
            return (FieldDef)src;
        }

        void GenerateBasicObject(SystemDef sysInfo, ObjectDef obj)
        {
            StringBuilder template = new StringBuilder(Properties.Resource1.class_basicobject);
            GenerateTemplateObject(template, sysInfo, obj);
        }

        void GenerateNamedObject(SystemDef sysInfo, ObjectDef obj)
        {
            StringBuilder template = new StringBuilder(Properties.Resource1.class_namedobject);
            GenerateTemplateObject(template, sysInfo, obj);
        }

        /// <summary>
        /// Generates the system policy.
        /// </summary>
        /// <param name="sysPolicy">The sys policy.</param>
        /// <param name="sysInfo">The sys info.</param>
        void GenerateSystemPolicy(SystemPolicyDef sysPolicy, SystemDef sysInfo)
        {
            GenerateConfigTemplate("SystemPolicy", sysPolicy.policys, sysInfo, sysPolicy.roles, sysPolicy.builtinRoles);
        }

        /// <summary>
        /// Generates the global settings.
        /// </summary>
        /// <param name="globalSettings">The global settings.</param>
        /// <param name="sysInfo">The sys info.</param>
        void GenerateGlobalSettings(GlobalSettingsDef globalSettings, SystemDef sysInfo)
        {
            GenerateConfigTemplate("GlobalSetting", globalSettings.settings, sysInfo, null, null);
        }

        /// <summary>
        /// Generates the config template.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="items">The items.</param>
        /// <param name="sysInfo">The sys info.</param>
        /// <param name="roles">The roles.</param>
        /// <param name="builtinRoles">The builtin roles.</param>
        void GenerateConfigTemplate(String name, List<ConfigItemDef> items, SystemDef sysInfo, List<RoleDef> roles, List<string> builtinRoles)
        {
            string objName = string.Format("{0}", name);
            string classFile = Path.Combine(outputFolder,
                string.Format("class_{0}.cs", objName));

            Console.WriteLine("Generating class {0} ({1})", objName, classFile);
            
            // Read the template from the resource file.
            StringBuilder template = new StringBuilder(Properties.Resource1.class_configobject);

            // Common strings
            StringBuilder fieldPriv = new StringBuilder();
            StringBuilder fieldProp = new StringBuilder();
            StringBuilder fieldLoad = new StringBuilder();
            StringBuilder fieldAssign = new StringBuilder();
            StringBuilder paramSave = new StringBuilder();
            StringBuilder paramSavePost = new StringBuilder();
            StringBuilder fieldReqParm = new StringBuilder();
            StringBuilder fieldReqSet = new StringBuilder();           
            StringBuilder customMethods = new StringBuilder();

            // Copy Helper Related strings
            StringBuilder copyArguments = new StringBuilder();
            StringBuilder copyAssignments = new StringBuilder();
            StringBuilder copyParams = new StringBuilder();
            StringBuilder copyMembers = new StringBuilder();
            StringBuilder copyPostSave = new StringBuilder();

            // Config objects Related strings
            StringBuilder confInterfaceProp = new StringBuilder();
            StringBuilder uiResInterfaceProp = new StringBuilder();
            StringBuilder fieldInstanceSet = new StringBuilder();
            StringBuilder uiResourceClass = new StringBuilder(Properties.Resource1.class_uiresources);            
            StringBuilder uiResourceFields = new StringBuilder();
            StringBuilder uiResourceProperties = new StringBuilder();            

            // Roles related
            StringBuilder builtinRolesInt = new StringBuilder();
            StringBuilder loadRoleColl = new StringBuilder();
            StringBuilder builtinSecRolesClass = new StringBuilder();
            StringBuilder builtinSecRolesProperties = new StringBuilder();
            StringBuilder rollCollRefresh = new StringBuilder();

            // Loop through each config item to generate the required strings.
            foreach (ConfigItemDef item in items)
            {
                // Creating a field out of the config item.
                FieldDef field = new FieldDef(item.Name, item.Type, item.Name, true);

                // Generate the field related strings.
                GenerateField(name, field, fieldReqParm, fieldPriv, fieldProp, fieldReqSet, fieldLoad, paramSave, fieldAssign, copyParams, false);

                // Generate the config item related strings.
                GenerateConfigItems(field, confInterfaceProp, uiResInterfaceProp, fieldInstanceSet);

                // Generate the UI Resources strings.
                GenerateUIResources(field.Name, item.UILocResource, item.UINolocResourceText, uiResourceFields, uiResourceProperties);
            }            

            if (roles != null)
            {                
                foreach (RoleDef role in roles)
                {
                    // Generate UI Resource fields for the roles.
                    GenerateUIResources(role.Name, role.UILocResource, role.UINolocResourceText, uiResourceFields, uiResourceProperties);
                    
                    // Fetch the builtin role for the user.
                    string builtinrole = GetBuiltinRoleType(role);

                    // Create the builtin roles string.
                    if (builtinrole != "None")
                    {
                        StringBuilder builtinRolesProp = new StringBuilder(Properties.Resource1.class_propertyget);
                        builtinRolesProp.Replace("%FIELD_TYPE%","ISecurityPrincipalColection");
                        builtinRolesProp.Replace("%FIELD_PUB%", builtinrole);
                        builtinRolesProp.Replace("%FIELD_PRIV%", string.Format("obj.{0}",role.Name));
                        builtinSecRolesProperties.AppendLine(builtinRolesProp.ToString());
                    }
                    
                    // Generate the config item related strings for the roles.
                    GenerateRoleConfigItems(role.Name, builtinrole, confInterfaceProp, uiResInterfaceProp, fieldInstanceSet, fieldPriv, fieldProp, rollCollRefresh);
                }
                
                // Adding the Everyone group.

                confInterfaceProp.AppendLine(string.Format("        {0} {1} {{ get; }}", "Group", "Everyone"));
                fieldInstanceSet.AppendLine(string.Format("                       instance.{0} = Group.Load(\"{1}\", c);", "everyone", "Everyone"));

                fieldPriv.AppendLine(string.Format("        private {0} {1};", "Group", "everyone"));

                StringBuilder propEveryoneText = new StringBuilder(Properties.Resource1.class_propertyget);
                propEveryoneText.Replace("%FIELD_TYPE%", "Group");
                propEveryoneText.Replace("%FIELD_PUB%", "Everyone");
                propEveryoneText.Replace("%FIELD_PRIV%", "everyone");

                propEveryoneText.Replace("%FIELD_PRIV%", "everyone");
                fieldProp.AppendLine(propEveryoneText.ToString());


                if (builtinRoles != null && builtinRoles.Count > 0)
                {
                    builtinRolesInt.AppendLine(Properties.Resource1.interface_builtin_roles);
                    StringBuilder builtinRolesTxt = new StringBuilder();

                    foreach (string builtinRole in builtinRoles)
                    {
                        if (builtinRole != "None")
                        {
                            builtinRolesTxt.AppendLine(string.Format("         {0} {1} {{ get; }}", "ISecurityPrincipalColection",
                            builtinRole));
                        }
                    }

                    builtinRolesInt.Replace("  %%BUILTIN_ROLES%%", builtinRolesTxt.ToString());
                    confInterfaceProp.AppendLine(string.Format("        {0} {1} {{ get; }}", "ISRBuiltinSecurityRoles", "Builtin"));
                    fieldPriv.AppendLine(string.Format("        {0} {1} {2};", "private", "ISRBuiltinSecurityRoles", "builtin"));
                    StringBuilder propText = new StringBuilder(Properties.Resource1.class_propertyget);
                    propText.Replace("%FIELD_TYPE%", "ISRBuiltinSecurityRoles");
                    propText.Replace("%FIELD_PUB%", "Builtin");
                    propText.Replace("%FIELD_PRIV%", "builtin");

                    fieldProp.AppendLine(propText.ToString());

                    builtinSecRolesClass.AppendLine(Properties.Resource1.class_builtin_roles);
                    builtinSecRolesClass.Replace("%%BUILTIN_SECURITY_ROLES_MEMBERS%%", builtinSecRolesProperties.ToString());
                    fieldInstanceSet.AppendLine("                       instance.builtin = new BuiltinSecurityRoles(instance);");
                    
                }

                StringBuilder prinColl = new StringBuilder();
                loadRoleColl.Append(Properties.Resource1.class_load_role_coll);
                for (int i = 0; i < securityPrincipalList.Count; i++)
                {
                    if (i > 0)
                        prinColl.Append("                     else ");
                    StringBuilder loadSecPrin = new StringBuilder(Properties.Resource1.class_load_sec_principal);
                    loadSecPrin.Replace("%PRINCIPAL%", securityPrincipalList[i]);
                    prinColl.AppendLine(loadSecPrin.ToString());
                }
                loadRoleColl.Replace("%%LOAD_SEC_PRINCIPAL%%", prinColl.ToString());
            }

            fieldInstanceSet.AppendLine("                       instance.uiresources = new UIDisplayResources();");
            
            uiResourceClass.Replace("%%UI_RESOURCES_FIELDS%% ", uiResourceFields.ToString());
            uiResourceClass.Replace("%%UI_RESOURCES_PROPERTIES%%", uiResourceProperties.ToString());
            
            
            StringBuilder copyCode = GenerateCopyClass(name, copyArguments, copyAssignments, copyParams, copyMembers, copyPostSave);

            // %%LOAD_METHODS%%
            StringBuilder loadMethods = new StringBuilder(Properties.Resource1.class_loadmethods);
            loadMethods.AppendLine(customMethods.ToString());

            //
            // Class code generation
            //                        
            
            StringBuilder classCode = template;
            classCode.Replace("%%BUILTIN_SECURITY_ROLES_CLASS%%", builtinSecRolesClass.ToString());
            classCode.Replace("%%ROLE_COLL_REFRESH%%", rollCollRefresh.ToString());
            classCode.Replace("%%LOAD_ROLE_COLLECTION%%", loadRoleColl.ToString());
            classCode.Replace("%%INTERFACE_BUILTIN_ROLES%%", builtinRolesInt.ToString().Replace("\t",""));
            classCode.Replace("%%CONFIG_INTERFACE_PROPS%%", confInterfaceProp.ToString());
            classCode.Replace("        %%RESOURCE_PROPS%%", uiResInterfaceProp.ToString());
            classCode.Replace("%%INSTANCE_FIELDS_REQ_SET%% ", fieldInstanceSet.ToString());
            classCode.Replace("%%UI_RESOURCES_CLASS%%", uiResourceClass.ToString());
            classCode.Replace("%%FIELDS_REQ%%, ", fieldReqParm.ToString().Replace("\r\n", ""));
            classCode.Replace("%IN_OVERRIDE% ", "");
            classCode.Replace("        %%FIELD_PROPERTIES%%\r\n", fieldProp.ToString());
            classCode.Replace("            %%FIELDS_REQ_SET%%", fieldReqSet.ToString());
            classCode.Replace("            %INDEX_VAR%\r\n",
                (fieldLoad.Length > 0 ? "            int index;\r\n" : ""));
            classCode.Replace("            %%FIELDS_LOAD%%\r\n", fieldLoad.ToString());
            classCode.Replace("		%%LOAD_METHODS%%", loadMethods.ToString());
            classCode.Replace("            %%PARAMETERS_SAVE%%\r\n", paramSave.ToString());
            classCode.Replace("            %%PARAMETERS_SAVE_POST%%\r\n", paramSavePost.ToString());

            classCode.Replace("        %%FIELD_PRIVATES%%\r\n", fieldPriv.ToString());            
            classCode.Replace("%SYSTEM%", sysInfo.Name);
            classCode.Replace("%OBJECT%", objName);
            classCode.Replace("        %%COPY_CLASS_CODE%%", copyCode.ToString());

            if (name.Equals("SystemPolicy"))
            {
                classCode.Replace("%SYSTEM_POLICY_INTERFACE%", ": ISystemSecurityPolicy");
            }
            else if (name.Equals("GlobalSetting"))
            {
                classCode.Replace("%SYSTEM_POLICY_INTERFACE%", "");
            }
            
            using (StreamWriter sw = new StreamWriter(classFile))
            {
                sw.Write(classCode);
            }
        }

        /// <summary>
        /// Gets the type of the builtin role.
        /// </summary>
        /// <param name="role">The role.</param>
        /// <returns></returns>
        private string GetBuiltinRoleType(RoleDef role)
        {
            string builtinRole = "None";
            switch (role.Type)
            {
                case config.roletype.builtinAdmins:
                    builtinRole = "Administrators";
                    break;
                case config.roletype.builtinGuests:
                    builtinRole = "Guests";
                    break;
                case config.roletype.builtinServices:
                    builtinRole = "Services";
                    break;
                case config.roletype.builtinUsers:
                    builtinRole = "Users";
                    break;

            }
            return builtinRole;
        }

        /// <summary>
        /// Generates the UI resources.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="uiLocResource">The UI loc resource.</param>
        /// <param name="uiNolocResourceText">The UI noloc resource text.</param>
        /// <param name="uiResourceFields">The UI resource fields.</param>
        /// <param name="uiResourceProperties">The UI resource properties.</param>
        void GenerateUIResources(string name, string uiLocResource, string uiNolocResourceText, StringBuilder uiResourceFields, StringBuilder uiResourceProperties)
        {
            uiResourceFields.AppendLine(string.Format("               private {0} ui{1}locres = \"{2}\";", "string", GetPrivateName(name),
            uiLocResource));

            uiResourceFields.AppendLine(string.Format("               private {0} {1}nolocrestxt = \"{2}\";", "string", GetPrivateName(name),
                  uiNolocResourceText));
            StringBuilder prop = new StringBuilder(Properties.Resource1.class_uiresprop);
            prop.Replace("%FIELDPROP%", GetPublicName(name));
            prop.Replace("%FIELD%", GetPrivateName(name));
            uiResourceProperties.Append(prop.ToString());
            uiResourceProperties.AppendLine();
        }

        /// <summary>
        /// Generates the config items.
        /// </summary>
        /// <param name="field">The field.</param>
        /// <param name="interfaceProp">The interface prop.</param>
        /// <param name="interfaceUIResProp">The interface UI res prop.</param>
        /// <param name="fieldInstanceSet">The field instance set.</param>
        void GenerateConfigItems(FieldDef field, StringBuilder confInterfaceProp, StringBuilder uiResInterfaceProp, StringBuilder fieldInstanceSet)
        {
            Type fieldType;
            DL.Parameter.ParamType paramType;
            string fieldGet;
            string fieldSave;             
                
            GetStoreType(field.Type, out paramType, out fieldType, out fieldGet, out fieldSave);

            // append to the config interface string.
            confInterfaceProp.AppendLine(string.Format("        {0} {1} {{ get; set; }}", fieldType,
            GetPublicName(field.Name)));

            // append to the UI interface string.
            uiResInterfaceProp.AppendLine(string.Format("        {0} {1}{2} {{ get; }}", "string",
            GetPublicName(field.Name), "Text"));
        }

        /// <summary>
        /// Generates the role config items.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="builtinRole">The builtin role.</param>
        /// <param name="interfaceProp">The interface prop.</param>
        /// <param name="interfaceUIResProp">The interface UI res prop.</param>
        /// <param name="fieldInstanceSet">The field instance set.</param>
        /// <param name="fieldPriv">The field priv.</param>
        /// <param name="fieldProp">The field prop.</param>
        void GenerateRoleConfigItems(string name, string builtinRole, StringBuilder interfaceProp, StringBuilder interfaceUIResProp, StringBuilder fieldInstanceSet, StringBuilder
            fieldPriv, StringBuilder fieldProp, StringBuilder rollCollRefresh)
        { 
            interfaceProp.AppendLine(string.Format("        {0} {1} {{ get; }}", "ISecurityPrincipalColection",
            GetPublicName(name)));

            interfaceUIResProp.AppendLine(string.Format("        {0} {1}{2} {{ get; }}", "string",
            GetPublicName(name), "Text"));

            rollCollRefresh.AppendLine(string.Format("                       this.{0} = new SecurityPrincipalCollection(LoadRoleCollection(SystemRoleType.{1}, Conn), SystemBuiltinRoleType.{2}, SystemRoleType.{1}, Conn);",
            GetPrivateName(name), GetPublicName(name), builtinRole));
            
            fieldInstanceSet.AppendLine(string.Format("                       instance.{0} = new SecurityPrincipalCollection(LoadRoleCollection(SystemRoleType.{1}, c), SystemBuiltinRoleType.{2}, SystemRoleType.{1}, c);",
            GetPrivateName(name), GetPublicName(name), builtinRole));

            fieldPriv.AppendLine(string.Format("        private {0} {1};", "ISecurityPrincipalColection",
                GetPrivateName(name)));

            StringBuilder propText = new StringBuilder(Properties.Resource1.class_propertyget);
            propText.Replace("%FIELD_TYPE%","ISecurityPrincipalColection");
            propText.Replace("%FIELD_PUB%",GetPublicName(name));
            propText.Replace("%FIELD_PRIV%", GetPrivateName(name));

            fieldProp.AppendLine(propText.ToString());


        }

        /// <summary>
        /// Generates the template object.
        /// </summary>
        /// <param name="template">The template.</param>
        /// <param name="sysInfo">The sys info.</param>
        /// <param name="obj">The obj.</param>
        void GenerateTemplateObject(StringBuilder template, SystemDef sysInfo, ObjectDef obj)
        {
            
            string objName = string.Format("{0}", obj.Name);
            string classFile = Path.Combine(outputFolder,
                string.Format("class_{0}.cs", objName));

            Console.WriteLine("Generating class {0} ({1})", objName, classFile);

            StringBuilder implDefs = new StringBuilder();
            // Contains 
            StringBuilder implMethods = new StringBuilder();
            StringBuilder collImplDefs = new StringBuilder();
            StringBuilder collImplMethods = new StringBuilder();            
            
            StringBuilder fieldPriv = new StringBuilder();
            StringBuilder fieldProp = new StringBuilder();
            StringBuilder fieldLoad = new StringBuilder();
            StringBuilder fieldAssign = new StringBuilder();
            StringBuilder paramSave = new StringBuilder();
            StringBuilder paramSavePost = new StringBuilder();

            StringBuilder fieldReqParm = new StringBuilder();
            StringBuilder fieldReqSet = new StringBuilder();
            StringBuilder versioningData = new StringBuilder("");

            StringBuilder customMethods = new StringBuilder();

            // Copy Helper Related strings
            StringBuilder copyArguments = new StringBuilder();
            StringBuilder copyAssignments = new StringBuilder();
            StringBuilder copyParams = new StringBuilder();
            StringBuilder copyMembers = new StringBuilder();
            StringBuilder copyPostSave = new StringBuilder();
            
            // Implementation for the Interface definitions.
            foreach (ImplDef impl in obj.Implements)
            {
                implDefs.AppendFormat(", {0}", impl.Interface);
                if (impl.Interface.Equals("ISecurityPrincipal"))
                {
                    implMethods.Append(Properties.Resource1.class_isecurityprincipal_members);
                }
            }

            // Implementation for the Collection Interface definitions.
            foreach (CollImplDef impl in obj.CollImplements)
            {
                collImplDefs.AppendFormat(", {0}", impl.Interface);
                if(impl.Interface.Equals("ISecurityCredentialCollection"))
                {
                    collImplMethods.Append(Properties.Resource1.class_securitycredentialcoll);
                }
            }

            foreach (FieldDef field in obj.Fields)
            {
                if (field.IsBLOB)
                    GenerateBlob(obj.Name, field, fieldReqParm, fieldPriv, fieldProp, fieldReqSet, fieldLoad, paramSave, paramSavePost, customMethods, copyPostSave, obj.Bindable);
                else
                    GenerateField(obj.Name, field, fieldReqParm, fieldPriv, fieldProp, fieldReqSet, fieldLoad, paramSave, fieldAssign, copyParams, obj.Bindable);
            }

            // we won't be adding this get binding method for Binding classes, blob classes and field enums
            StringBuilder bindable = new StringBuilder();
            StringBuilder bindableObjectInit = new StringBuilder();
            if (obj.Bindable)
            {
                GenerateBindings(obj, ref bindable);
                bindableObjectInit.AppendLine(string.Format("{0}Binding binding = null;", objName));
            }

            foreach (EnumDef field in obj.Enums)
            {
                GenerateEnum(obj.Name, field, fieldReqParm, fieldReqSet, fieldPriv, fieldProp, fieldLoad, paramSave, fieldAssign, copyParams);
            }

            // If the SecPrincipalRefDef is required add as a required field in the constructor.
            foreach (SecPrincipalRefDef mySecPrinRef in obj.SecPrinRef)
            {
                if (mySecPrinRef.Required)
                {
                    fieldReqParm.AppendLine(string.Format("{0} {1}, ",
                        mySecPrinRef.Type, GetPrivateName(mySecPrinRef.Name)));

                    for (int i = 0; i < securityPrincipalList.Count; i++)
                    {
                        if (i > 0)
                        {
                            fieldReqSet.Append("                     else ");
                        }
                        string principal = securityPrincipalList[i];
                        String fieldName = string.Format("{0}{1}{2}", mySecPrinRef.Name, principal, "Principal");
                        StringBuilder fieldPropSrc = new StringBuilder(Properties.Resource1.class_secprinref);
                        fieldPropSrc.Replace("%FIELD_NAME%", GetPrivateName(mySecPrinRef.Name));
                        fieldPropSrc.Replace("%FIELD%", GetPrivateName(fieldName));
                        fieldPropSrc.Replace("%PRINCIPAL%", principal);
                        fieldReqSet.Append(fieldPropSrc);
                        fieldReqSet.AppendLine();
                    }                    
                }               
            }

            // Construction logic for ISecurable objects.
            if (obj.SecPrivDef != null)
            {   
                fieldReqParm.AppendLine(string.Format("{0} {1}, ",
                        obj.SecPrivDef.Type, "priv"));
                foreach (string priv in obj.SecPrivDef.PrivPermMapping.Keys)                
                {  
                    StringBuilder privPropSrc = new StringBuilder(Properties.Resource1.class_secprivconstruction);
                    privPropSrc.Replace("%OBJECT%", obj.SecPrivDef.Name);
                    privPropSrc.Replace("%PRIV%", priv);
                    StringBuilder permStr = new StringBuilder();
                    foreach (string perm in obj.SecPrivDef.PrivPermMapping[priv])
                    {   
                        StringBuilder permPropSrc = new StringBuilder(Properties.Resource1.class_secpermconstruction);
                        permPropSrc.Replace("%OBJECT%", obj.SecPrivDef.Name);
                        permPropSrc.Replace("%PRIV%", priv);
                        permPropSrc.Replace("%PERM%", perm);
                        permPropSrc.Replace("%PERM_FIELD%", "permission");
                        String privilege = string.Format("{0}{1}", perm, "priv");
                        permPropSrc.Replace("%PRIV_FIELD%", GetPrivateName(privilege));                        
                        permStr.Append(permPropSrc);
                        permStr.AppendLine();
                    }
                    privPropSrc.Replace("%%PERM_CHECKS%%", permStr.ToString());     
                    fieldReqSet.Append(privPropSrc);
                    fieldReqSet.AppendLine();
                }
            }

            foreach (RefDef myRef in obj.References)
            {   
                if (myRef.Required)
                {
                    fieldReqParm.AppendLine(string.Format("{0} {1}, ",
                        myRef.Type, GetPrivateName(myRef.Name)));
                    fieldReqSet.AppendLine(string.Format("            newObj.{0} = {0};",
                        GetPrivateName(myRef.Name)));
                }


                // %%FIELD_PRIVATES%%
                fieldPriv.AppendLine(string.Format("        private Guid {0}ID;", GetPrivateName(myRef.Name)));
                fieldPriv.AppendLine(string.Format("        private {0} {1};", myRef.Type, GetPrivateName(myRef.Name)));

                // %%PARAMETERS_SAVE%%
                paramSave.AppendLine(string.Format("            mydata.Add(new Parameter(\"{0}\", Parameter.ParamType.Guid, Parameter.ParamDirection.In, ",
                    myRef.SQLName, GetPublicName(myRef.Name)));
                paramSave.AppendLine(string.Format("                (this.{0}ID == Guid.Empty ?", GetPrivateName(myRef.Name)));                    
                paramSave.AppendLine(string.Format("                (this.{1} == null ? Guid.Empty : ((IObject)this.{1}).ID)",
                    myRef.SQLName, GetPublicName(myRef.Name)));
                paramSave.AppendLine(string.Format("                : this.{0}ID)));", GetPrivateName(myRef.Name)));                

                // %%COPYPARAMETER%%
                copyParams.AppendLine(string.Format("			     mydata.Add(new Parameter(\"{0}\", Parameter.ParamType.Guid, Parameter.ParamDirection.In, ",
                    myRef.SQLName, GetPrivateName(myRef.Name)));
                copyParams.AppendLine(string.Format("				    (this.{1} == null ? Guid.Empty : ((IObject)this.{1}).ID)));",
                    myRef.SQLName, GetPrivateName(myRef.Name)));

                    
                // Generate the load from DB
                StringBuilder fieldLoadSrc = new StringBuilder(Properties.Resource1.class_fieldload);
                fieldLoadSrc.Replace("%FIELD_STORE%", myRef.SQLName);
                fieldLoadSrc.Replace("%FIELD_TYPE%", "Guid");
                fieldLoadSrc.Replace("%FIELD_PRIV%", string.Format("{0}ID", GetPrivateName(myRef.Name)));
                fieldLoadSrc.Replace("%FIELD_GET%", "GetGuid");
                fieldLoad.Append(fieldLoadSrc);
                fieldLoad.AppendLine();


                // %%FIELD_PROPERTIES%%
                StringBuilder fieldPropSrc = new StringBuilder(Properties.Resource1.class_refproperty);
                fieldPropSrc.Replace("%FIELD_VIS%", myRef.Visibility.ToString());
                fieldPropSrc.Replace("%FIELD_TYPE%", myRef.Type);
                fieldPropSrc.Replace("%FIELD_PUB%", GetPublicName(myRef.Name));
                fieldPropSrc.Replace("%FIELD_PRIV%", GetPrivateName(myRef.Name));
                fieldProp.Append(fieldPropSrc);
                fieldProp.AppendLine();
                // %%COPY_ARGUMENTS%%
                copyArguments.Append(string.Format("{0} {1},", myRef.Type, GetPrivateName(myRef.Name)));
                copyAssignments.AppendLine(string.Format("                this.{0}={0};", GetPrivateName(myRef.Name)));
                copyMembers.AppendLine(string.Format("            {0} {1};", myRef.Type, GetPrivateName(myRef.Name)));
            }

            // if this class is a binding class, let's add external resource binding code here
            if (obj.Name.EndsWith("Binding"))
            {
                // add the binding code. 
                StringBuilder bindingMethods = new StringBuilder(Properties.Resource1.class_bindings);
                customMethods.Append(bindingMethods);
                customMethods.AppendLine();

            }

            if (copyArguments.Length > 0)
                copyArguments.Remove(copyArguments.Length - 1, 1);

            StringBuilder relClear = new StringBuilder();
            StringBuilder relRefresh = new StringBuilder();
            StringBuilder relPriv = new StringBuilder();
            StringBuilder relLoad = new StringBuilder();
            StringBuilder relEmpty = new StringBuilder();
            StringBuilder relProp = new StringBuilder();

            if (obj.Relations.Count > 0)
            {
                relEmpty.AppendLine("            // Empty collections");
            }

            foreach (RelationDef rel in obj.Relations)
            {
                string relName = rel.IsSelfRelation ? rel.OtherFieldName(RelationDef.RelationDirection.One)
                    : rel.OtherName(rel.ObjectClassName(obj.Name));
                string relPrivName = GetPrivateName(relName);
                string relPubName = GetPublicName(relName);
                string relType = rel.ObjectClassName(obj.Name);
                string relVis = "public";

                string relOtherName2 = rel.OtherName2(obj.Name);

                if (rel.IsSelfRelation)
                {
                    if (rel.IsTwoWay)
                        GenerateRelation(objName, relType, relName, relPrivName, relPubName, rel.OneName, rel.TwoName, relVis, "_1", relPriv, relProp, relLoad, relRefresh, relEmpty, relClear);
                    else
                        GenerateRelation(objName, relType, relName, relPrivName, relPubName, null, relName, relVis, "_1", relPriv, relProp, relLoad, relRefresh, relEmpty, relClear);
                }
                else
                {
                    GenerateRelation(objName, relType, relName, relPrivName, relPubName, null, null, relVis, "", relPriv, relProp, relLoad, relRefresh, relEmpty, relClear);
                }

                if (rel.IsSelfRelation && rel.IsTwoWay)
                {
                    // We are a self-relationship. Generate the reverse relation
                    string revRelName = rel.OtherFieldName(RelationDef.RelationDirection.Two);
                    string revRelPrivName = GetPrivateName(revRelName);
                    string revRelPubName = GetPublicName(revRelName);
                    string revRelType = rel.ObjectClassName(obj.Name);
                    string revRelVis = rel.Visibility.ToString();

                    GenerateRelation(objName, revRelType, revRelName, revRelPrivName, revRelPubName, rel.TwoName, rel.OneName, revRelVis, "_2", relPriv, relProp, relLoad, relRefresh, relEmpty, relClear);
                }
            }
            StringBuilder copyCode = GenerateCopyClass(GetPublicName(obj.Name), copyArguments, copyAssignments, copyParams, copyMembers, copyPostSave);

            // Reverse Relations (Reference -> Type -> Relation)
            foreach (RefDef ref1 in obj.RevRef)
            {
                string relName = ref1.RevName ?? ref1.Source.Name;
                string relPrivName = GetPrivateName(relName);
                string relPubName = GetPublicName(relName);
                string relType = ref1.Source.Name;
                string relKey = ref1.StoreAs ?? ref1.Name;
                string relRevKey = ref1.RevName ?? ref1.Source.Name;
                string relVis = ref1.RevVisibility.ToString();

                GenerateRelation(objName, relType, relName, relPrivName, relPubName, relKey, relRevKey, relVis, "", relPriv, relProp, relLoad, relRefresh, relEmpty, relClear);
            }

            // %%LOAD_METHODS%%
            StringBuilder loadMethods = new StringBuilder(Properties.Resource1.class_loadmethods);
            loadMethods.AppendLine(customMethods.ToString());

            // %%SEARCH%%
            StringBuilder search = new StringBuilder(Properties.Resource1.class_search);
            StringBuilder searchUsing = new StringBuilder(Properties.Resource1.class_search_using);
            GenerateSearch(obj, ref search, ref searchUsing);

            //
            // Class code generation
            //

            StringBuilder classCode = template;
            classCode.Replace("%%FIELDS_REQ%%, ", fieldReqParm.ToString().Replace("\r\n", ""));

            switch (obj.Parent)
            {
                case config.objectParent.BasicObject:                
                case config.objectParent.@object:
                    classCode.Replace("%IN_OVERRIDE% ", "");
                    break;
                case config.objectParent.NamedObject:
                    classCode.Replace("%IN_OVERRIDE% ", (fieldReqParm.Length == 0 ? "new " : ""));
                    break;
                default:
                    throw new NotImplementedException("Unknown parent class type");
            }

            if (obj.Securable != null)
            {
                fieldLoad.AppendLine(string.Format("            loadObj.security = new %OBJECT%.ISecurity(loadObj, c);"));
                fieldReqSet.AppendLine(string.Format("            newObj.security = new %OBJECT%.ISecurity(newObj, c);"));
                fieldAssign.AppendLine(string.Format("            newObj.Owner = this.Owner;"));
                fieldAssign.AppendLine(string.Format("            newObj.security = new Activity.ISecurity(newObj, c);"));
            }
            if (obj.Versioned)
            {
                GenerateVersioningHelpers(objName, fieldReqParm.ToString().Replace("\r\n", ""), fieldAssign.ToString(),
                    fieldReqSet.ToString(), relEmpty.ToString(), versioningData);
            }
            classCode.Replace("%%OBJECT_BINDING_INIT%%", bindableObjectInit.ToString());
            classCode.Replace(" %%COLL_IMPL_DEFS%%", collImplDefs.ToString());
            classCode.Replace(" %%COLL_IMPL_METHODS%%", collImplMethods.ToString());
            classCode.Replace(" %%IMPL_DEFS%%", implDefs.ToString());
            classCode.Replace(" %%IMPL_METHODS%%", implMethods.ToString());
            classCode.Replace("            %%FIELDS_REQ_SET%%", fieldReqSet.ToString());
            classCode.Replace("        %%FIELD_PRIVATES%%\r\n", fieldPriv.ToString());
            classCode.Replace("        %%FIELD_PROPERTIES%%\r\n", fieldProp.ToString());
            classCode.Replace("            %%FIELDS_LOAD%%\r\n", fieldLoad.ToString());
            classCode.Replace("            %%PARAMETERS_SAVE%%\r\n", paramSave.ToString());
            classCode.Replace("            %%PARAMETERS_SAVE_POST%%\r\n", paramSavePost.ToString());
            classCode.Replace("        %%RELATION_PRIVATES%%\r\n", relPriv.ToString());
            classCode.Replace("        %%RELATION_PROPERTIES%%\r\n", relProp.ToString());
            classCode.Replace("        %%VERSIONING_HELPERS%%\r\n", versioningData.ToString());
            classCode.Replace("            %%RELATIONS_LOAD%%\r\n", relLoad.ToString());
            classCode.Replace("            %%RELATIONS_REFRESH%%\r\n", relRefresh.ToString());
            classCode.Replace("            %%RELATIONS_CLEAR%%\r\n", relClear.ToString());
            classCode.Replace("            %%EMPTY_RELATIONS%%\r\n", relEmpty.ToString());
            classCode.Replace("            %INDEX_VAR%\r\n",
                (fieldLoad.Length > 0 ? "            int index;\r\n" : ""));
            classCode.Replace("		%%LOAD_METHODS%%", loadMethods.ToString());
            classCode.Replace("		%%SEARCH%%\r\n", search.ToString());
            classCode.Replace("%%SEARCH_USING%%\r\n", searchUsing.ToString());
            classCode.Replace("		%%BINDABLE%%\r\n", bindable.ToString());

            classCode.Replace("%SYSTEM%", sysInfo.Name);
            classCode.Replace("%OBJECT_VIS%", obj.Visibility.ToString());
            classCode.Replace("%OBJECT%", objName);
            classCode.Replace("        %%COPY_CLASS_CODE%%", copyCode.ToString());
            using (StreamWriter sw = new StreamWriter(classFile))
            {
                sw.Write(classCode);
            }            
        }

        private static void GenerateBindings(ObjectDef obj, ref StringBuilder bindings)
        {
            Console.WriteLine(" Adding Databinding related class and methods to {0}", obj.Name);
            // if not add the code to retrieve bindings

            StringBuilder getBindingMethod = new StringBuilder(Properties.Resource1.class_getbinding);

            bindings.Append(getBindingMethod);
            bindings.AppendLine();

            StringBuilder fieldsEnum = new StringBuilder();

            obj.Fields.ForEach(field =>
                {
                    if (obj.Fields.IndexOf(field) == 0)
                    {
                        fieldsEnum.Append(field.Name);
                    }
                    else
                    {
                        fieldsEnum.Append(string.Format(",\r\n                {0}", field.Name));
                    }
                });

            if (obj.BaseClass == ParentClasses.NamedObject.ToString())
            {
                // Generate the "Name" search field
                fieldsEnum.Append(",\r\n                Name");
            }

            bindings.AppendLine();

            bindings.Replace("%%BINDABLE_FIELD_DECLS%%", fieldsEnum.ToString());
        }

        StringBuilder GenerateCopyClass(string objName, StringBuilder copyArguments, StringBuilder copyAssignments,
            StringBuilder copyParams, StringBuilder copyMembers, StringBuilder copyPostSave)
        {
            StringBuilder copyClassCode = new StringBuilder(Properties.Resource1.class_copyhelper);
            copyClassCode.Replace("%%COPYSOURCEOBJECT%%", objName);
            copyClassCode.Replace("%%COPYSOURCEOBJECTINSTANCE%%", GetPrivateName(objName));

            copyClassCode.Replace("%%COPY_ARGUMENTS%%", copyArguments.ToString());
            copyClassCode.Replace("                %%COPY_ASSIGNMENTS%%", copyAssignments.ToString());
            copyClassCode.Replace("				%%COPY_PARAMS%%", copyParams.ToString());
            copyClassCode.Replace("            %%COPY_MEMBERS%%", copyMembers.ToString());
            copyClassCode.Replace("                %%COPYPARAMETERS_SAVE_POST%%", copyPostSave.ToString());

            StringBuilder copyCall = new StringBuilder();
            if (copyArguments.Length == 0)
            {
                copyClassCode.Replace("            %%COPYCALL%%", "         CopyHelper helper = new CopyHelper();");
                copyClassCode.Replace("%%COPYCLASS%%", "");
            }
            else
            {
                copyClassCode.Replace("            %%COPYCALL%%", "");
                copyClassCode.Replace("%%COPYCLASS%%", ",CopyHelper helper");
            }
            return copyClassCode;
        }

        void GenerateVersioningHelpers(string objName, string reqFields, string fieldAssign, string fieldReqSet,
            string emptyRels, StringBuilder versioningHelpers)
        {
            StringBuilder versionSrc = new StringBuilder(Properties.Resource1.class_versioning_helpers);

            versionSrc.Replace("%IN_OVERRIDE%", "");
            versionSrc.Replace("%OBJECT%", objName);

            versionSrc.Replace("            %%FIELD_ASSIGN%%\r\n", fieldAssign);
            versionSrc.Replace("            %%EMPTY_RELATIONS%%\r\n", emptyRels);

            versioningHelpers.Append(versionSrc);
            versioningHelpers.AppendLine();
        }

        void GenerateField(string objName, FieldDef field, StringBuilder fieldReqParm, StringBuilder fieldPriv,
            StringBuilder fieldProp, StringBuilder fieldReqSet, StringBuilder fieldLoad,
            StringBuilder paramSave, StringBuilder fieldAssign, StringBuilder copyParams,
            bool IsBindable)
        {
            Type fieldType;
            DL.Parameter.ParamType paramType;
            string fieldGet;
            string fieldSave;

            GetStoreType(field.Type, out paramType, out fieldType, out fieldGet, out fieldSave);

            if (field.Required)
            {
                fieldReqParm.AppendLine(string.Format("{0} {1}, ",
                    fieldType, GetPrivateName(field.Name)));
                fieldReqSet.AppendLine(string.Format("            newObj.{0} = {0};",
                    GetPrivateName(field.Name)));
            }

            // %%FIELD_PRIVATES%%
            fieldPriv.AppendLine(string.Format("        private {0} {1};", fieldType.ToString(),
                GetPrivateName(field.Name)));


            // %%FIELD_ASSIGN%%
            fieldAssign.AppendLine(string.Format("            newObj.{0} = this.{1};",
                GetPrivateName(field.Name), GetPrivateName(field.Name)));

            // %%FIELD_PROPERTIES%%
            StringBuilder fieldPropSrc;
            if (IsBindable)
            {
                fieldPropSrc = new StringBuilder(Properties.Resource1.class_bound_property);
                fieldPropSrc.Replace("%FIELD_TYPE_SHORT_NAME%", fieldType.Name);
            }
            else
            {
                fieldPropSrc = new StringBuilder(Properties.Resource1.class_property);
            }

            // %%PARAMETERS_SAVE%%
            if (IsBindable)
            {
                StringBuilder parameterSaveProperty = new StringBuilder(Properties.Resource1.class_bound_save_parameter);
                parameterSaveProperty.Replace(
                    "%%SAVE_PARAMETER%%",
                    Serializer.EmitSaveParam(field.Type, field, paramType, GetPrivateName(field.Name), GetPublicName(field.Name)));


                parameterSaveProperty.Replace("%FIELD_PUB%", GetPublicName(field.Name));
                parameterSaveProperty.Replace("%FIELD_PRIV%", GetPrivateName(field.Name));

                paramSave.AppendLine(parameterSaveProperty.ToString());
                paramSave.AppendLine();
            }
            else
            {
                paramSave.AppendLine(Serializer.EmitSaveParam(field.Type, field, paramType, GetPrivateName(field.Name), GetPublicName(field.Name)));
                paramSave.AppendLine();
            }

            fieldPropSrc.Replace("%FIELD_TYPE%", fieldType.ToString());
            fieldPropSrc.Replace("%FIELD_PUB%", GetPublicName(field.Name));
            fieldPropSrc.Replace("%FIELD_PRIV%", GetPrivateName(field.Name));
            fieldProp.Append(fieldPropSrc);
            fieldProp.AppendLine();

            // %%FIELDS_LOAD%%
            StringBuilder fieldLoadSrc = Serializer.EmitLoadCode(field.Type);

            fieldLoadSrc.Replace("%FIELD_STORE%", field.SQLName);
            fieldLoadSrc.Replace("%FIELD_TYPE%", fieldType.ToString());
            fieldLoadSrc.Replace("%FIELD_PRIV%", GetPrivateName(field.Name));
            fieldLoadSrc.Replace("%FIELD_GET%", fieldGet);
            fieldLoad.Append(fieldLoadSrc);
            fieldLoad.AppendLine();

            // %%COPYPARAMETER%%
            copyParams.AppendLine(Serializer.EmitCopyParam(GetPrivateName(objName), field.Type, field, paramType, GetPrivateName(field.Name), GetPublicName(field.Name)));
        }

        void GenerateBlob(string owner, FieldDef field, StringBuilder fieldReqParm, StringBuilder fieldPriv,
                 StringBuilder fieldProp, StringBuilder fieldReqSet, StringBuilder fieldLoad,
                 StringBuilder paramSave, StringBuilder paramSavePost, StringBuilder customMethods, StringBuilder copyPostSave,
                bool IsBindable)
        {
            Type fieldType;
            DL.Parameter.ParamType paramType;
            string fieldGet;
            string fieldSave;

            GetStoreType(field.Type, out paramType, out fieldType, out fieldGet, out fieldSave);

            // %%FIELD_PRIVATES%%
            fieldPriv.AppendLine(string.Format("        private {0} {1};", fieldType.ToString(),
                GetPrivateName(field.Name)));
            fieldPriv.AppendLine(string.Format("        private bool {1}Loaded = false;", fieldType.ToString(),
                GetPrivateName(field.Name)));
            fieldPriv.AppendLine(string.Format("        private bool {1}Changed = false;", fieldType.ToString(),
                GetPrivateName(field.Name)));

            // %%FIELD_PROPERTIES%%
            StringBuilder fieldPropSrc;
            fieldPropSrc = new StringBuilder(Properties.Resource1.class_common_property_blob);

            StringBuilder getBlobProperty;
            StringBuilder setBlobProperty;
            if (IsBindable)
            {
                // Get property change.
                getBlobProperty = new StringBuilder(Properties.Resource1.class_bound_property_blob);
                getBlobProperty.Replace("					%LOAD_FROM_BLOB%", Properties.Resource1.class_property_blob);
            }
            else
            {
                // Get property change.
                getBlobProperty = new StringBuilder(Properties.Resource1.class_property_blob);
            }

            // %%PARAMETERS_SAVE%%
            if (IsBindable)
            {
                StringBuilder parameterSaveBlob = new StringBuilder(Properties.Resource1.class_bound_save_parameter);
                parameterSaveBlob.Replace(
                    "%%SAVE_PARAMETER%%",
                    Serializer.EmitSaveParam(field.Type, field, paramType, GetPrivateName(field.Name), GetPublicName(field.Name)));

                parameterSaveBlob.Replace("%FIELD_PUB%", GetPublicName(field.Name));
                parameterSaveBlob.Replace("%FIELD_PRIV%", GetPrivateName(field.Name));

                paramSavePost.AppendLine(parameterSaveBlob.ToString());
                paramSavePost.AppendLine();
            }
            else
            {
                paramSavePost.AppendLine(Serializer.EmitSaveParam(field.Type, field, paramType, GetPrivateName(field.Name), GetPublicName(field.Name)));
                paramSavePost.AppendLine();
            }

            // Set property change.
            setBlobProperty = new StringBuilder(Properties.Resource1.class_property_set_blob);

            fieldPropSrc.Replace("				%GET_BLOB_DATA%", getBlobProperty.ToString());
            fieldPropSrc.Replace("                %SET_BLOB_DATA%", setBlobProperty.ToString());

            fieldPropSrc.Replace("%FIELD_TYPE%", fieldType.ToString());
            fieldPropSrc.Replace("%FIELD_PUB%", GetPublicName(field.Name));
            fieldPropSrc.Replace("%FIELD_PRIV%", GetPrivateName(field.Name));
            fieldPropSrc.Replace("%FIELD_GET%", fieldGet);
            fieldProp.Append(fieldPropSrc);
            fieldProp.AppendLine();

            // %%CUSTOM_METHODS%%
            StringBuilder customSrc = new StringBuilder(Properties.Resource1.class_blob_store);
            customSrc.Replace("            %%BLOB_STORE_CONV%%\r\n", fieldSave);
            customSrc.Replace("%FIELD_TYPE%", fieldType.ToString());
            customSrc.Replace("%FIELD_PUB%", GetPublicName(field.Name));
            customSrc.Replace("%FIELD_PRIV%", GetPrivateName(field.Name));
            customSrc.Replace("%FIELD_GET%", fieldGet);
            customMethods.Append(customSrc);
            customMethods.AppendLine();

            // %%COPYPARAMETERS_SAVE_POST%%
            copyPostSave.AppendLine(Serializer.EmitCopyParam(GetPrivateName(owner), field.Type, field, paramType, GetPrivateName(field.Name), GetPublicName(field.Name)));
        }

        void GenerateEnum(string objName, EnumDef field, StringBuilder fieldReqParm, StringBuilder fieldReqSet, StringBuilder fieldPriv,
            StringBuilder fieldProp, StringBuilder fieldLoad, StringBuilder paramSave, StringBuilder fieldAssign, StringBuilder copyParams)
        {
            if (field.Required)
            {
                fieldReqParm.AppendLine(string.Format("{0} {1}, ",
                    field.EnumType, GetPrivateName(field.Name)));
                fieldReqSet.AppendLine(string.Format("            newObj.{0} = {0};",
                    GetPrivateName(field.Name)));
            }

            // %%FIELD_PRIVATES%%
            fieldPriv.AppendLine(string.Format("        private {0} {1};", field.EnumType,
                GetPrivateName(field.Name)));

            // %%FIELD_ASSIGN%%
            fieldAssign.AppendLine(string.Format("            newObj.{0} = this.{1};",
                GetPrivateName(field.Name), GetPrivateName(field.Name)));

            // %%FIELD_PROPERTIES%%
            StringBuilder fieldPropSrc = new StringBuilder(Properties.Resource1.class_property);
            fieldPropSrc.Replace("%FIELD_TYPE%", field.EnumType);
            fieldPropSrc.Replace("%FIELD_PUB%", field.Name);
            fieldPropSrc.Replace("%FIELD_PRIV%", GetPrivateName(field.Name));
            fieldProp.Append(fieldPropSrc);
            fieldProp.AppendLine();

            // %%FIELDS_LOAD%%
            StringBuilder fieldLoadSrc = new StringBuilder(Properties.Resource1.class_enumload);
            fieldLoadSrc.Replace("%FIELD_STORE%", field.SQLName);
            fieldLoadSrc.Replace("%FIELD_TYPE%", field.EnumType);
            fieldLoadSrc.Replace("%FIELD_PRIV%", GetPrivateName(field.Name));
            fieldLoad.Append(fieldLoadSrc);
            fieldLoad.AppendLine();

            // %%PARAMETERS_SAVE%%
            paramSave.AppendLine(string.Format("            mydata.Add(new Parameter(\"{0}\", Parameter.ParamType.String, Parameter.ParamDirection.In, this.{1}.ToString()));",
                field.SQLName, GetPrivateName(field.Name)));

            // %%COPYPARAMETER%%
            copyParams.AppendLine(string.Format("                 mydata.Add(new Parameter(\"{0}\", Parameter.ParamType.String, Parameter.ParamDirection.In, {2}.{1}.ToString()));",
                field.SQLName, GetPrivateName(field.Name), objName.ToLower()));
        }

        void GenerateRelation(string objName, string relType, string relName, string relPrivName, string relPubName,
            string relKeyField, string relRevKeyField,
            string relVisibility, string relationSuffix,
            StringBuilder relPriv, StringBuilder relProp, StringBuilder relLoad,
            StringBuilder relRefresh, StringBuilder relEmpty, StringBuilder relClear)
        {
            string plural = "s";

            if (relPrivName.ToLower().Equals("children"))
                plural = "";

            // %%RELATION_PRIVATES%%
            relPriv.AppendLine(string.Format("        private {1}Collection<{2}> {0}" + plural + ";", relPrivName, relType, objName));

            // %%RELATION_PROPERTIES%%
            relProp.AppendLine(string.Format("        {4} {1}Collection<{2}> {3}" + plural + " {{ get {{ return {0}" + plural + "; }} }}",
                relPrivName, relType, objName, relPubName, relVisibility));

            // %%RELATIONS_LOAD%%
            relLoad.AppendLine(string.Format("            // {0}" + plural + "", relName));
            relLoad.AppendLine(string.Format("            loadObj.{0}" + plural + " = {1}Collection<{2}>.CreateFromReader(loadObj, {3}{4}reader, c);",
                relPrivName, relType, objName,
                relKeyField == null && relRevKeyField == null ? "" :
                    string.Format("{0}, {1}, ",
                        relKeyField == null ? "null" : string.Format("\"{0}\"", relKeyField),
                        relRevKeyField == null ? "null" : string.Format("\"{0}\"", relRevKeyField)),
                        string.IsNullOrEmpty(relationSuffix) ? "" : string.Format("\"{0}\", ", objName + relationSuffix)));

            // %%RELATIONS_REFRESH%%
            relRefresh.AppendLine(string.Format("            this.{0}" + plural + ".Refresh();", relPrivName));

            // %%EMPTY_RELATIONS%%
            relEmpty.AppendLine(string.Format("            newObj.{0}" + plural + " = new {1}Collection<{2}>(newObj, {3}{4}c);",
                relPrivName, relType, objName,
                relKeyField == null && relRevKeyField == null ? "" :
                    string.Format("{0}, {1}, ",
                        relKeyField == null ? "null" : string.Format("\"{0}\"", relKeyField),
                        relRevKeyField == null ? "null" : string.Format("\"{0}\"", relRevKeyField)),
                        string.IsNullOrEmpty(relationSuffix) ? "" : string.Format("\"{0}\", ", objName + relationSuffix)));

            if (relKeyField != null)
            {
                //if (!isParent)
                //{
                //    // %%RELATIONS_CLEAR%%
                //    relClear.AppendLine(string.Format("            if( this.{0}" + plural + ".Count > 0 )", relPrivName));
                //    relClear.AppendLine(string.Format("                throw new ObjectInUseException(\"Object in use\");"));
                //}
                //else
                //{
                //    // FOREACH.... DELETE
                //    relClear.AppendLine(string.Format("        asddsafsd    if( this.{0}" + plural + ".Count > 0 )", relPrivName));
                //    relClear.AppendLine(string.Format("                throw new ObjectInUseException(\"Object in use\");"));
                //}
            }
            else
            {
                // %%RELATIONS_CLEAR%%
                relClear.AppendLine(string.Format("            this.{0}" + plural + ".Clear();", relPrivName));
            }
        }

        void GenerateRelationObject(SystemDef sysInfo, RelationDef rel)
        {
            if (rel.Object == null)
            {
                throw new ApplicationException("Cannot generate relation object to non object binding relations");
            }

            string objName = string.Format("{0}", rel.Object);

            string relFile = Path.Combine(outputFolder,
                string.Format("rel_{0}.cs", objName));

            Console.WriteLine("Generating relation object {0}[{2}] ({1})", rel.Object, relFile, rel.Two);

            StringBuilder fieldPriv = new StringBuilder();
            StringBuilder fieldProp = new StringBuilder();
            StringBuilder fieldAssign = new StringBuilder();
            StringBuilder fieldLoad = new StringBuilder();
            StringBuilder paramSave = new StringBuilder();
            StringBuilder paramSavePost = new StringBuilder();

            StringBuilder fieldReqParm = new StringBuilder();
            StringBuilder fieldReqSet = new StringBuilder();

            StringBuilder customMethods = new StringBuilder();
            StringBuilder copyParam = new StringBuilder();
            StringBuilder copySavePost = new StringBuilder();

            if (rel.Fields != null)
            {
                // Fields for the relation
                foreach (FieldDef field in rel.Fields)
                {
                    if (field.IsBLOB)
                        GenerateBlob(objName, field, fieldReqParm, fieldPriv, fieldProp, fieldReqSet, fieldLoad, paramSave, paramSavePost, customMethods, copySavePost, false);
                    else
                        GenerateField(objName, field, fieldReqParm, fieldPriv, fieldProp, fieldReqSet, fieldLoad, paramSave, fieldAssign, copyParam, false);
                }
            }

            if (rel.Enums != null)
            {
                // Enums for the relation
                foreach (EnumDef myEnum in rel.Enums)
                {
                    GenerateEnum(objName, myEnum, fieldReqParm, fieldReqSet, fieldPriv, fieldProp, fieldLoad, paramSave, fieldAssign, copyParam);
                }
            }

            // if this class is a binding class, let's add external resource binding code here
            if (rel.Object.EndsWith("Binding"))
            {
                // add the binding code. 
                StringBuilder bindingMethods = new StringBuilder(Properties.Resource1.class_bindings);
                customMethods.Append(bindingMethods);
                customMethods.AppendLine();
            }

            StringBuilder loadMethods = customMethods;

            //
            // Relation object generation
            //

            string oneName = rel.One;
            string twoName = rel.Two;

            if (rel.One == rel.Two)
            {
                // N:N Self Relationship
                oneName = string.Format("{0}_1", oneName);
                twoName = string.Format("{0}_2", twoName);
            }

            StringBuilder relCode = null;
            if (rel.IsSelfRelation)
                relCode = new StringBuilder(Properties.Resource1.class_relobject_helpers);
            else
                relCode = new StringBuilder(Properties.Resource1.rel_object);

            relCode.Replace("%%FIELDS_REQ%%, ", fieldReqParm.ToString().Replace("\r\n", ""));
            relCode.Replace("            %%FIELDS_REQ_SET%%", fieldReqSet.ToString());
            relCode.Replace("		%%LOAD_METHODS%%", loadMethods.ToString());
            relCode.Replace("        %%FIELD_PRIVATES%%\r\n", fieldPriv.ToString());
            relCode.Replace("        %%FIELD_PROPERTIES%%\r\n", fieldProp.ToString());
            relCode.Replace("            %%FIELDS_LOAD%%\r\n", fieldLoad.ToString());
            relCode.Replace("            %%PARAMETERS_SAVE%%\r\n", paramSave.ToString());
            relCode.Replace("            %%PARAMETERS_SAVE_POST%%\r\n", paramSavePost.ToString());
            relCode.Replace("            %INDEX_VAR%\r\n",
                (fieldLoad.Length > 0 ? "            int index;\r\n" : ""));

            relCode.Replace("%OBJECT%", objName);
            relCode.Replace("%SYSTEM%", sysInfo.Name);
            relCode.Replace("%ONE%", rel.One);
            relCode.Replace("%ONE_NAME%", oneName);
            relCode.Replace("%TWO%", rel.Two);
            relCode.Replace("%TWO_NAME%", twoName);

            using (StreamWriter sw = new StreamWriter(relFile))
            {
                sw.Write(relCode);
            }
        }

        void GenerateEnumTypes(SystemDef sysInfo, List<EnumDef> enumList)
        {
            string enumTypeFile = Path.Combine(outputFolder,
                string.Format("type_{0}Enums.cs", sysInfo.Name));

            StringBuilder enumCodeList = new StringBuilder();

            foreach (EnumDef myEnum in enumList)
            {
                // Don't add the CredentialType definition as this is already defined as a 
                // data layer common enum.
                if (myEnum.Values.Count > 0 && myEnum.EnumType != "CredentialType")
                {
                    Console.WriteLine("Generating enum {0}", myEnum.EnumType);

                    StringBuilder enumValues = new StringBuilder();

                    foreach (string enumValue in myEnum.Values)
                    {
                        enumValues.AppendLine(string.Format("        {0},", enumValue));
                    }

                    StringBuilder enumDef = new StringBuilder(Properties.Resource1.type_enumdef);
                    enumDef.Replace("%TYPE%", myEnum.EnumType);
                    enumDef.Replace("        %%ENUM_VALUES%%\r\n", enumValues.ToString());

                    if (enumCodeList.Length > 0)
                        enumCodeList.AppendLine();

                    enumCodeList.Append(enumDef);
                }
                else
                {
                    Console.WriteLine("Skipping over enum {0}. No <Value> defined", myEnum.EnumType);
                }
            }

            if (enumCodeList.Length == 0)
            {
                Console.WriteLine("Skipping enum generation. No <Value> defined");
            }
            else
            {
                StringBuilder enumCode = new StringBuilder(Properties.Resource1.type_enums);
                enumCode.Replace("    %%ENUM_DEFS%%\r\n", enumCodeList.ToString());

                using (StreamWriter sw = new StreamWriter(enumTypeFile))
                {
                    sw.Write(enumCode);
                }
            }
        }

        void GenerateSearch(ObjectDef obj, ref StringBuilder search, ref StringBuilder searchUsing)
        {
            List<string> stubsTypes = new List<string>();
            StringBuilder stubsDefs = new StringBuilder();
            StringBuilder fieldDecl = new StringBuilder();
            StringBuilder fieldHlpr = new StringBuilder();

            if (!obj.IsBlobStore)
            {
                if (obj.BaseClass == ParentClasses.NamedObject.ToString())
                {
                    // Generate the "Name" search field
                    GenerateSearchField(obj, "Name", config.datatype.@string, ref fieldDecl, ref fieldHlpr, ref stubsTypes);
                }

                //
                // Generate common fields for all objects
                //
                // IMPORTANT: DO NOT ADD "ID" (IObject.ID) TO THIS LIST!!! That will only encourage developers to perform
                //            searches using ID more than necessary. To find by id call Object.Load(Guid)
                //                                                      -- Nelson Araujo
                //
                GenerateSearchField(obj, "CreatedDate", config.datatype.dateTime, ref fieldDecl, ref fieldHlpr, ref stubsTypes);
                GenerateSearchField(obj, "CreatedBy", config.datatype.@string, ref fieldDecl, ref fieldHlpr, ref stubsTypes);
                GenerateSearchField(obj, "UpdatedDate", config.datatype.dateTime, ref fieldDecl, ref fieldHlpr, ref stubsTypes);
                GenerateSearchField(obj, "UpdatedBy", config.datatype.@string, ref fieldDecl, ref fieldHlpr, ref stubsTypes);

                foreach (FieldDef field in obj.Fields)
                {
                    GenerateSearchField(obj, field.Name, field.Type, ref fieldDecl, ref fieldHlpr, ref stubsTypes);
                }

                foreach (EnumDef _enum in obj.Enums)
                {
                    // Add to stub list for generating necessary stubs for fields
                    if (!stubsTypes.Contains("EnumField<>"))
                        stubsTypes.Add("EnumField<>");

                    fieldDecl.AppendLine(string.Format("                public static FieldDefs.EnumField<{0}> {1} = new FieldDefs.EnumField<{0}>(\"{1}\");",
                        _enum.EnumType, _enum.Name));
                    fieldHlpr.AppendLine(string.Format("            public static ISearchClause {1}(EnumField<{0}>.Condition op, {0} value) {{ return Fields.{1}.CreateSearchClause(op, value); }}",
                        _enum.EnumType, _enum.Name));
                }

                foreach (RefDef _ref in obj.References)
                {
                    // Add to stub list for generating necessary stubs for fields
                    if (!stubsTypes.Contains("ObjectField<>"))
                        stubsTypes.Add("ObjectField<>");

                    fieldDecl.AppendLine(string.Format("                public static FieldDefs.ObjectField<{0}> {1} = new FieldDefs.ObjectField<{0}>(\"{1}\");",
                        _ref.Type, _ref.Name));
                    fieldHlpr.AppendLine(string.Format("            public static ISearchClause {1}(ObjectField<{0}>.Condition op, {0} value) {{ return Fields.{1}.CreateSearchClause(op, value); }}",
                        _ref.Type, _ref.Name));
                }

                foreach (RelationDef _rel in obj.Relations)
                {
                    // Add to stub list for generating necessary stubs for fields
                    string relName = _rel.OtherName(_rel.Other(_rel.One));
                    string relOtherName2 = _rel.OtherName2(obj.Name);

                    string otherObject = _rel.OtherObjectName(obj.Name);
                    string otherFieldName = _rel.OtherSearchName(obj.Name);

                    string relationType = "RelationFieldBase.RelationshipType.Simple";
                    string stubType = "RelationSimpleField";
                    string relField = string.Empty;
                    //string relName = _rel.TwoSearchName();
                    //string relOtherName2 = _rel.OneSearchName();

                    //string otherObject = _rel.OtherObjectName(obj.Name);
                    //string otherFieldName = _rel.OtherSearchName(obj.Name);

                    //string relationType = "RelationFieldBase.RelationshipType.Simple";
                    //string stubType = "RelationSimpleField";
                    //string relField = string.Empty;

                    if (string.IsNullOrEmpty(_rel.Object))
                    {
                        if (_rel.IsSelfRelation)
                        {

                            relationType = "RelationFieldBase.RelationshipType.Parent";

                            relField = string.Format("                public static FieldDefs.{2}<{0}> {1} = new FieldDefs.{2}<{0}>(\"{1}\", {3});",
                                otherObject, _rel.OtherFieldName(RelationDef.RelationDirection.One), stubType, relationType);
                            fieldDecl.AppendLine(relField);
                            relField = string.Format("            public static ISearchClause {1}({2}<{0}>.Condition op, {0} value) {{ return Fields.{1}.CreateSearchClause(op, value); }}",
                                otherObject, _rel.OtherFieldName(RelationDef.RelationDirection.One), stubType);

                            fieldHlpr.AppendLine(relField);

                            relationType = "RelationFieldBase.RelationshipType.Child";
                            relField = string.Format("                public static FieldDefs.{2}<{0}> {0} = new FieldDefs.{2}<{0}>(\"{1}\", {3});",
                                    otherObject, _rel.OtherFieldName(RelationDef.RelationDirection.Two), stubType, relationType);
                            fieldDecl.AppendLine(relField);
                            relField = string.Format("            public static ISearchClause {1}({2}<{0}>.Condition op, {0} value) {{ return Fields.{1}.CreateSearchClause(op, value); }}",
                               otherObject, _rel.OtherFieldName(RelationDef.RelationDirection.Two), stubType);

                        }
                        else
                        {
                            //public static FieldDefs.RelationSimpleField<Tag> Tag = new FieldDefs.RelationSimpleField<Tag>("Keyword", RelationFieldBase.RelationshipType.Simple);
                            relField = string.Format("                public static FieldDefs.{2}<{0}> {1} = new FieldDefs.{2}<{0}>(\"{1}\", {3});",
                                otherObject, otherFieldName, stubType, relationType);
                            fieldDecl.AppendLine(relField);
                            //public static ISearchClause Tag(RelationSimpleField<Keyword>.Condition op, Tag value) { return Fields.Tag.CreateSearchClause(op, value); }
                            relField = string.Format("            public static ISearchClause {1}({2}<{0}>.Condition op, {0} value) {{ return Fields.{1}.CreateSearchClause(op, value); }}",
                                otherObject, otherFieldName, stubType);

                        }
                    }
                    //Object Field
                    else
                    {
                        stubType = "RelationObjectField";

                        if (_rel.IsSelfRelation)
                        {
                            relationType = "RelationFieldBase.RelationshipType.Parent";
                            relField = string.Format("                public static FieldDefs.{2}<{0}> {1} = new FieldDefs.{2}<{0}>(\"{1}\", \"{3}\", {4});",
                                otherObject, _rel.OtherFieldName(RelationDef.RelationDirection.One), stubType, _rel.TableName, relationType);
                            fieldDecl.AppendLine(relField);
                            relField = string.Format("            public static ISearchClause {1} ({2}<{0}>.Condition op, {0} value) {{ return Fields.{1}.CreateSearchClause(op, value); }}",
                                otherObject, _rel.OtherFieldName(RelationDef.RelationDirection.One), stubType);

                            fieldHlpr.AppendLine(relField);

                            relationType = "RelationFieldBase.RelationshipType.Child";
                            relField = string.Format("                public static FieldDefs.{2}<{0}> {1} = new FieldDefs.{2}<{0}>(\"{1}\", \"{3}\", {4});",
                                otherObject, _rel.OtherFieldName(RelationDef.RelationDirection.Two), stubType, _rel.TableName, relationType);
                            fieldDecl.AppendLine(relField);
                            relField = string.Format("            public static ISearchClause {1} ({2}<{0}>.Condition op, {0} value) {{ return Fields.{1}.CreateSearchClause(op, value); }}",
                                otherObject, _rel.OtherFieldName(RelationDef.RelationDirection.Two), stubType);

                        }
                        else
                        {
                            relField = string.Format("                public static FieldDefs.{2}<{0}> {1} = new FieldDefs.{2}<{0}>(\"{1}\", \"{4}\", {3});",
                                otherObject, otherFieldName, stubType, relationType, _rel.TableName);
                            fieldDecl.AppendLine(relField);
                            relField = string.Format("            public static ISearchClause {1}({2}<{0}>.Condition op, {0} value) {{ return Fields.{1}.CreateSearchClause(op, value); }}",
                                otherObject, otherFieldName, stubType);
                        }
                    }
                    stubType += "<>";
                    if (!stubsTypes.Contains(stubType))
                        stubsTypes.Add(stubType);

                    fieldHlpr.AppendLine(relField);
                }
            }
            else
            {
                // No search on blob units
                search = new StringBuilder();
                searchUsing = new StringBuilder();
            }

            //
            // Process and generate necessary stubs
            //
            string stubFactory = Properties.Resource1.class_search_fielddefs;
            List<string> stubFactoryCode = new List<string>(stubFactory.Replace("\r", "").Split('\n'));
            foreach (string stubType in stubsTypes)
            {
                // Extract stub from factory
                int codeStart = stubFactoryCode.IndexOf(string.Format("[[{0}[START[", stubType));
                int codeEnd = stubFactoryCode.IndexOf(string.Format("]END]{0}]]", stubType));

                // Copy the code section to class
                for (int i = codeStart + 1; i < codeEnd; i++)
                    stubsDefs.AppendLine(stubFactoryCode[i]);
            }

            search.Replace("				%%SEARCH_FIELD_STUBS%%\r\n", stubsDefs.ToString());
            search.Replace("                %%SEARCH_FIELD_DECLS%%\r\n", fieldDecl.ToString());
            search.Replace("            %%SEARCH_FIELD_HELPERS%%\r\n", fieldHlpr.ToString());
        }

        void GenerateSearchField(ObjectDef obj, string name, config.datatype classType, ref StringBuilder fieldDecl, ref StringBuilder fieldHlpr,
                                    ref List<string> stubsTypes)
        {
            Dictionary<config.datatype, string> searchClassMap = new Dictionary<config.datatype, string>();
            Dictionary<config.datatype, System.Type> searchCondMap = new Dictionary<config.datatype, System.Type>();

            searchClassMap[config.datatype.@string] = "StringField";
            searchClassMap[config.datatype.integer] = "IntegerField";
            searchClassMap[config.datatype.text] = "StringField";
            searchClassMap[config.datatype.dateTime] = "DateTimeField";
            searchClassMap[config.datatype.boolean] = "BooleanField";
            searchClassMap[config.datatype.color] = null;                       // skip search for "Color"
            searchClassMap[config.datatype.image] = null;                       // skip search for "Image"
            searchClassMap[config.datatype.byteArray] = null;                   // skip search for "ByteArray"
            searchClassMap[config.datatype.uri] = "URIField";
            searchClassMap[config.datatype.guid] = null;                        // skip search for "Guid"

            searchCondMap[config.datatype.@string] = typeof(string);
            searchCondMap[config.datatype.integer] = typeof(int);
            searchCondMap[config.datatype.text] = typeof(string);
            searchCondMap[config.datatype.dateTime] = typeof(DateTime);
            searchCondMap[config.datatype.boolean] = typeof(bool);
            searchCondMap[config.datatype.color] = null;                        // skip search for "Color"
            searchCondMap[config.datatype.image] = null;                        // skip search for "Image"
            searchCondMap[config.datatype.byteArray] = null;                    // skip search for "ByteArray"
            searchCondMap[config.datatype.uri] = typeof(Uri);
            searchCondMap[config.datatype.guid] = null;                         // skip search for "Guid"

            if (!searchClassMap.ContainsKey(classType) || !searchCondMap.ContainsKey(classType))
            {
                Console.Error.WriteLine("FATAL: Type '{0}' is not defined for search compiler in {1}::{2}", classType, obj.Name, name);
                throw new ApplicationException(string.Format("FATAL: Type '{0}' is not defined for search compiler in {1}::{2}", classType, obj.Name, name));
            }

            if (searchClassMap[classType] != null && searchCondMap[classType] != null)
            {
                GenerateSearchField(name, searchClassMap[classType], searchCondMap[classType], ref fieldDecl, ref fieldHlpr, ref stubsTypes);
            }
        }

        void GenerateSearchField(string name, string classType, object condType, ref StringBuilder fieldDecl, ref StringBuilder fieldHlpr,
                                    ref List<string> stubsTypes)
        {
            // Add to stub list for generating necessary stubs for fields
            if (!stubsTypes.Contains(classType))
                stubsTypes.Add(classType);

            fieldDecl.AppendLine(string.Format("                public static FieldDefs.{0} {1} = new FieldDefs.{0}(\"{1}\");",
                classType, name));
            fieldHlpr.AppendLine(string.Format("            public static ISearchClause {1}({0}.Condition op, {2} value) {{ return Fields.{1}.CreateSearchClause(op, value); }}",
                classType, name, condType));
        }

        //---------------------------------------------------------------------------------------------------

        string GetPublicName(string field)
        {
            return string.Format("{0}{1}", field[0].ToString().ToUpperInvariant(), field.Substring(1));
        }        

        string GetPrivateName(string field)
        {
            if (field.ToLowerInvariant() == "namespace")
                field = "m_namespace";

            return field.ToLowerInvariant();
        }

        void GetStoreType(C.datatype src, out DL.Parameter.ParamType paramType,
            out Type dotNetField, out string fieldGet, out string fieldSave)
        {
            switch (src)
            {
                case config.datatype.boolean:
                    fieldGet = "GetBoolean";
                    fieldSave = "";
                    dotNetField = typeof(bool);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.Boolean;
                    break;
                case config.datatype.dateTime:
                    fieldGet = "GetDateTime";
                    fieldSave = "";
                    dotNetField = typeof(DateTime);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.DateTime;
                    break;
                case config.datatype.guid:
                    fieldGet = "GetGuid";
                    fieldSave = "";
                    dotNetField = typeof(Guid);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.Guid;
                    break;
                case config.datatype.integer:
                    fieldGet = "GetInt32";
                    fieldSave = "";
                    dotNetField = typeof(int);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.Int;
                    break;
                case config.datatype.@string:
                    fieldGet = "GetString";
                    fieldSave = "";
                    dotNetField = typeof(string);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.String;
                    break;
                case config.datatype.uri:
                    fieldGet = "GetString";
                    fieldSave = "";
                    dotNetField = typeof(Uri);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.String;
                    break;
                case config.datatype.text:
                    fieldGet = "GetString";
                    fieldSave = "";
                    dotNetField = typeof(string);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.Text;
                    break;
                case config.datatype.color:
                    fieldGet = "GetInt32";
                    fieldSave = "";
                    dotNetField = typeof(System.Drawing.Color);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.Color;
                    break;
                case config.datatype.image:
                    fieldGet = "System.Drawing.Image.FromStream";
                    fieldSave = Properties.Resource1.class_blob_store_img;
                    dotNetField = typeof(System.Drawing.Image);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.Image;
                    break;
                case config.datatype.byteArray:
                    fieldGet = "BlobBase.StreamToByteArray";
                    fieldSave = Properties.Resource1.class_blob_store_bytearr;
                    dotNetField = typeof(byte[]);
                    paramType = Microsoft.Research.DataLayer.Parameter.ParamType.Text;
                    break;
                default:
                    throw new NotImplementedException("Unknown type '" + src + "'");
            }
        }
    }
}
